$dh.Require("util/event");
DHDRAG = new DHEvent();
$dh.extend(DHDRAG, {
    mouseOffset: null, activeObj: null, mask: null, dragStarted: false,

    init: function() {
        $dh.addEv(document, "mousemove", DHDRAG.mouseMove);
        $dh.addEv(document, "mouseup", DHDRAG.mouseUp);
        $dh.addEv(document, "mousedown", DHDRAG.mouseDown);
        $dh.addEv(document, "mouseout", DHDRAG.mouseOut);

        // Further use as an DHT object
        $dh.setDrag = DHDRAG.setDrag;
        $dh.disableDrag = DHDRAG.disableDrag;
        // Create mask
        DHDRAG.mask = $dh.$new("div", { id: "_DHDragMask_" });
        $dh.css(DHDRAG.mask, { zIndex: 1000000, background: "yellow", opac: 30, position: "absolute", display: "none" });
        $dh.addCh(document.body, DHDRAG.mask);
    },

    setDrag: function(obj, dragParams) { //Eg: {mode : "MOVE", dragSource:parent, maskStyle:"", limit:{}, ghostDrag:true, noMask: false} 
        DHDRAG.setDragParams(obj, dragParams);
        DHDRAG.raise("_oninitdrag", obj);
    },
    setDragTarget: function(src, tar) { src.dragTarget = tar; },
    setDragParams: function(obj, dragParams) {
        var src = dragParams.dragSource || obj;
        src.canDrag = true;
        if (src != obj) src.dragTarget = obj;

        if (dragParams.mode.charAt(dragParams.mode.length - 1) != ",")
            dragParams.mode += ",";
        obj.dragParams = dragParams;
        $dh.preventLeak(obj, "dragParams");
    },
    disableDrag: function(obj) {
        obj.canDrag = false;
        obj.dragParams = null;
    },

    mouseDown: function(ev) {
        ev = $dh.normEv(ev);
        var src = ev.target;
        if (src.canDrag != true) return false;
        ev.stop();
        DHDRAG.activeObj = src.dragTarget || src;
        DHDRAG.dragSource = src;
        DHDRAG.dragStarted = false;
    },

    mouseUp: function(ev) {
        if ($dh.isNone(DHDRAG.activeObj)) return;
        DHDRAG.dragStarted = false;
        DHDRAG.raise("_ondragstop", DHDRAG.activeObj, $dh.normEv(ev));
        DHDRAG.mask.style.cursor = "";
        DHDRAG.activeObj = null;
    },

    mouseMove: function(ev) {
        ev = $dh.normEv(ev);
        // Raise public mouse move event
        if (ev.target.canDrag == true && $dh.isNone(DHDRAG.activeObj))
            DHDRAG.raise("_onmousemove", ev.target.dragTarget || ev.target, ev);
        // Raise drag start event       
        if ($dh.isNone(DHDRAG.activeObj)) return;
        if (DHDRAG.dragStarted != true) {
            DHDRAG.dragStarted = true;
            DHDRAG.raise("_ondragstart", DHDRAG.activeObj, ev);
        }
        if (DHDRAG.dragStarted)
            DHDRAG.raise("_ondragging", DHDRAG.activeObj, ev);
    },
    
    mouseOut: function(ev) {
        var tar = $dh.normEv(ev).target;
        if (!DHDRAG.dragStarted && tar.saveSrcCursor) {
            tar.style.cursor = tar.saveSrcCursor;
        }
        if (!DHDRAG.dragStarted) document.body.style.cursor = "";
    },
    
    addMode: function(name, modeObj) {
        if ($dh.isNone(DHDRAG["modes"]))
            DHDRAG.modes = new Array();
        DHDRAG.modes[name] = modeObj;
        modeObj.name = name;

        for (var p in modeObj) {
            if (p.indexOf("on") == 0) {
                var func = (modeObj[p] + "");
                var header = func.substr(0, func.indexOf("{") + 1);

                var newFunc = header +
                            "if (!DHDRAG.hasDragMode(arguments[1],'" + name + "')) return false;" +
                            "if (DHDRAG.modes['" + name + "']['" + p + "'].apply(DHDRAG,arguments) != false)" +
                                "DHDRAG.raise('" + p.toLowerCase() + "',arguments[1],arguments[2]);" +
                            "}";
                eval("DHDRAG.addEv('_" + p.toLowerCase() + "', " + newFunc + ")");
            }
        }
    },
    hasDragMode: function(obj, mode) {
        if (!obj.dragParams) return false;
        return obj.dragParams.mode.indexOf(mode + ",") >= 0;
    },
    msOffset: function(ev, obj) {
        ev = ev || window.event;
        var objPos = $dh.pos(obj), msPos = $dh.msPos(ev);
        return { left: msPos.left - objPos.left, top: msPos.top - objPos.top };
    }
});

// Register DHDRAG to window.onload
$dh.addLoader(DHDRAG.init);
$dh.addEv(window,"unload",function(){
    $dh.rmEv(document,"mousemove",DHDRAG.mouseMove);
    $dh.rmEv(document,"mouseup",DHDRAG.mouseUp);
    $dh.rmEv(document, "mousedown", DHDRAG.mouseDown);    
    for (var x in DHDRAG) 
        if (!$dh.isNone(DHDRAG[x])) DHDRAG[x] = null;
    DHDRAG = null;
});

// Register built-in effects
DHDRAG.addMode("RESIZE", {
    onInitDrag: function(sender, target) {
        var pp = ["width", "height"];
        for (var i = 0; i < pp.length; i++) {
            target.dragParams["min" + pp[i]] = target.dragParams["min" + pp[i]] || 0;
            target.dragParams["max" + pp[i]] = target.dragParams["max" + pp[i]] || 99999;
        }
    },
    onMouseMove: function(sender, target, ev) {
        if (DHDRAG.dragStarted && DHDRAG.activeObj)
            return false;

        var dragSource = ev.target;
        if (!target.saveSrcCursor)
            dragSource.saveSrcCursor = dragSource.style.cursor || "";

        var b = $dh.bounds(target);
        var pos = ev.pos;
        var d = target.dragParams.dResize || 6;

        document.body.style.cursor = "";
        var dir = { s: false, n: false, w: false, e: false };
        if (Math.abs(pos.left - b.left) <= d) { dir["w"] = true; }
        if (Math.abs(pos.left - b.left - b.width) <= d) { dir["e"] = true; }
        if (Math.abs(pos.top - b.top) <= d) { dir["n"] = true; }
        if (Math.abs(pos.top - b.top - b.height) <= d) { dir["s"] = true; }

        // Set cursor
        var csr = "";
        for (var p in dir) if (dir[p]) csr += p;
        if (csr != "") document.body.style.cursor = csr + "-resize";

        if (document.body.style.cursor.indexOf("-") > 0) {
            dragSource.style.cursor = document.body.style.cursor;
        }
        else {
            if (DHDRAG.activeObj == target)
                dragSource.style.cursor = dragSource.saveSrcCursor;
            else {
                dragSource.style.cursor = "";
                dragSource.saveSrcCursor = null;
            }
        }        
    },
    onDragStart: function(sender, target, ev) {
        if (target.dragParams.currentDragMode || document.body.style.cursor.indexOf("-resize")<0) {
            return false;
        }

        target.dragParams.currentDragMode = "RESIZE";
        target.dragParams.resizeMode = document.body.style.cursor;
        DHDRAG.mouseOffset = DHDRAG.msOffset(ev, target);
        DHDRAG.saveBounds = $dh.bounds(target);
        DHDRAG.saveMousePos = $dh.msPos(ev);
        if (target.dragParams.noMask != true)
            DHDRAG.mask.style.display = "";
        else {
            DHDRAG.mask.style.cursor = document.body.style.cursor;
        }
    },

    onDragStop: function(sender, target, ev) {
        if (target.dragParams.currentDragMode != "RESIZE") 
            return false;
        target.style.display = "";
        if (DHDRAG.mask.style.display == "none") return;        
        var newBounds = $dh.bounds(DHDRAG.mask);
        $dh.css(target, { display: "", size: [newBounds.width, newBounds.height], pos: [newBounds.left, newBounds.top] });
        DHDRAG.mask.style.display = "none";
        target.dragParams.currentDragMode = null;
        target.dragParams.resizeMode = null;
    },

    onDragging: function(sender, target, ev) {
        if (target.dragParams.currentDragMode != "RESIZE") 
            return false;
        var mousePos = ev.pos;
        var mb = { left: DHDRAG.saveBounds.left, top: DHDRAG.saveBounds.top, width: DHDRAG.saveBounds.width, height: DHDRAG.saveBounds.height };
        var dw = mousePos.left - DHDRAG.mouseOffset.left - DHDRAG.saveBounds.left;
        var dh = mousePos.top - DHDRAG.mouseOffset.top - DHDRAG.saveBounds.top;
        var dl = 0, dt = 0, lim = "";
        // Set delta for all sides
        var rsm = target.dragParams.resizeMode;
        switch (rsm.substr(0, rsm.indexOf("-"))) {
            case "w": dl = dw; dw = -dw; dh = 0; lim = "left&&width"; break;
            case "sw": dl = dw; dw = -dw; lim = "left&&width"; break;
            case "e": dh = 0; lim = "width"; break;
            case "ne": dt = dh; dh = -dh; lim = "top&&left&&height"; break;
            case "n": dt = dh; dh = -dh; dw = 0; lim = "top&&height"; break;
            case "s": dw = 0; lim = "height"; break;
            case "nw": dl = dw; dw = -dw; dt = dh; dh = -dh; lim = "top&&height&&width&&left"; break;
        }

        mb.width = dw + DHDRAG.saveBounds.width;
        mb.height = dh + DHDRAG.saveBounds.height;
        mb.top = dt + DHDRAG.saveBounds.top;
        mb.left = dl + DHDRAG.saveBounds.left;

        // Recheck limits
        var xlim = lim.split("&&");
        var related = { "width": "left", "height": "top", "top": "height", "left": "width" };
        for (var x in mb) {
            if (mb[x] < target.dragParams["min" + x]) {
                if (lim.indexOf(x) >= 0) {
                    for (var k = 0; k < xlim.length; k++)
                        if (related[x] == xlim[k])
                        mb[xlim[k]] += mb[x] - target.dragParams["min" + x];
                }
                mb[x] = target.dragParams["min" + x];
            }
            if (mb[x] > target.dragParams["max" + x]) {
                if (lim.indexOf(x) >= 0) {
                    for (var k = 0; k < xlim.length; k++)
                        if (related[x] == xlim[k])
                        mb[xlim[k]] += mb[x] - target.dragParams["max" + x]; ;
                }
                mb[x] = target.dragParams["max" + x];
            }
        }

        if (target.dragParams.ghostDrag != true) {
            $dh.pos(target, [mb.left, mb.top]);
            $dh.size(target, [mb.width, mb.height]);
        }
        //if (DHDRAG.mask.style.display != "none") {
        $dh.pos(DHDRAG.mask, [mb.left, mb.top]);
        $dh.size(DHDRAG.mask, [mb.width, mb.height]);
        //}
    }
});

// Define drag effects
DHDRAG.addMode("MOVE", {
    onInitDrag: function(sender, target) {
        var pp = ["left", "top"];
        for (var i = 0; i < pp.length; i++) {
            target.dragParams["min" + pp[i]] = target.dragParams["min" + pp[i]] || -99999;
            target.dragParams["max" + pp[i]] = target.dragParams["max" + pp[i]] || 99999;
        }
    },
    onDragStart: function(sender, target, ev) {
        if (target.dragParams.currentDragMode) 
            return false;
        alert("vao move");
        target.dragParams.currentDragMode = "MOVE";
        DHDRAG.mouseOffset = DHDRAG.msOffset(ev, target);
        if (target.dragParams.noMask != true) {
	        DHDRAG.mask.style.cursor = "move";
	        DHDRAG.mask.style.display = "";
	    }
	    var size = $dh.size(target);
	    $dh.size(DHDRAG.mask, [size.width, size.height]);
    },
    
    onDragStop: function(sender, target, ev) {
        if (target.dragParams.currentDragMode != "MOVE") 
            return false;
        target.style.display = "";
        if (target.dragParams.ghostDrag == true)
            $dh.css(target, {left: DHDRAG.mask.style.left, top: DHDRAG.mask.style.top});
        DHDRAG.mask.style.display = "none";
        target.dragParams.currentDragMode = null;
    },

    onDragging: function(sender, target, ev) {
        if (target.dragParams.currentDragMode != "MOVE") 
            return false;
        var mousePos = ev.pos;
        var newPos = {};
        newPos.left = mousePos.left - DHDRAG.mouseOffset.left;
        newPos.top = mousePos.top - DHDRAG.mouseOffset.top;
        for (var p in newPos) {
            if (newPos[p] > target.dragParams["max"+p]) newPos[p] = target.dragParams["max"+p];
            if (newPos[p] < target.dragParams["min"+p]) newPos[p] = target.dragParams["min"+p];
        }
    	$dh.pos(DHDRAG.mask,[newPos.left, newPos.top]);
    	if (target.dragParams.ghostDrag != true)
    	    $dh.pos(target, [newPos.left, newPos.top]);
    }
});